use chrono::Local;
use sq_global::{APP_ENV_CFG, APP_LOG_NAME_CFG, APP_LOG_PATH_CFG};
use tracing::Level;
use tracing_appender::non_blocking::WorkerGuard;
use tracing_subscriber::fmt::format::Writer;
use tracing_subscriber::fmt::{FormatEvent, FormatFields};
use tracing_subscriber::registry::LookupSpan;
use tracing_subscriber::{self, fmt};

const RED: &'static str = "\x1b[31m";
const YELLOW: &'static str = "\x1b[33m";
const BLUE: &'static str = "\x1b[34m";
const CYAN: &'static str = "\x1b[36m";
const RESET: &'static str = "\x1b[0m";

fn colorize(level: &Level) -> (&'static str, &'static str) {
    match *level {
        Level::ERROR => (RED, RESET),
        Level::WARN => (YELLOW, RESET),
        Level::INFO => (BLUE, RESET),
        Level::DEBUG | Level::TRACE => (CYAN, RESET),
    }
}

impl CustomFormatter {
    fn write_file_path(&self, file: &str, writer: &mut Writer<'_>) -> std::fmt::Result {
        let idx = file
            .rfind("/src")
            .and_then(|pos| file[..pos].rfind("/"))
            .unwrap_or(0);

        match idx {
            0 => write!(writer, "/{}:", file),
            _ => write!(writer, "{}:", &file[idx..]),
        }
    }
}

struct CustomFormatter;

impl<S, N> FormatEvent<S, N> for CustomFormatter
where
    S: tracing::Subscriber + for<'a> LookupSpan<'a>,
    N: for<'a> FormatFields<'a> + 'static,
{
    fn format_event(
        &self,
        ctx: &fmt::FmtContext<'_, S, N>,
        mut writer: Writer<'_>,
        event: &tracing::Event<'_>,
    ) -> std::fmt::Result {
        // 时间格式化
        let now = Local::now();
        write!(writer, "{} ", now.format("%Y-%m-%d %H:%M:%S%.3f"))?;

        // 日志级别
        let metadata = event.metadata();
        let level = metadata.level();
        let (color, reset) = colorize(level);
        write!(writer, "{}{:5}{} ", color, level, reset)?;

        // 线程信息
        write!(writer, "{:0>2?} ", std::thread::current().id())?;

        // 文件和行号，这里处理路径
        if let Some(file) = metadata.file() {
            self.write_file_path(file, &mut writer)?;
        }
        if let Some(line) = metadata.line() {
            write!(writer, "{} ", line)?;
        }

        // 事件字段
        ctx.format_fields(writer.by_ref(), event)?;
        writeln!(writer)
    }
}

pub fn init() -> WorkerGuard {
    let env = sq_config::get_unchecked::<String>(APP_ENV_CFG);
    let (appender, work_guard) = match env.eq("test") {
        false => tracing_appender::non_blocking(std::io::stdout()),
        true => {
            let appender = tracing_appender::rolling::daily(
                sq_config::get_unchecked::<String>(APP_LOG_PATH_CFG),
                sq_config::get_unchecked::<String>(APP_LOG_NAME_CFG),
            );
            tracing_appender::non_blocking(appender)
        }
    };

    // 初始化并设置日志格式(定制和筛选日志)
    tracing_subscriber::fmt()
        // .with_max_level(Level::DEBUG)
        .event_format(CustomFormatter)
        .with_writer(appender)
        .init(); // 初始化并将SubScriber设置为全局SubScriber
    work_guard
}
